package com.disgruntledbots;

import java.util.Random;
import java.util.ArrayList;

import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import org.andengine.engine.Engine;
import org.andengine.engine.FixedStepEngine;
import org.andengine.engine.LimitedFPSEngine;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.camera.ZoomCamera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RelativeResolutionPolicy;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.scene.background.IBackground;
import org.andengine.entity.sprite.Sprite;
import org.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.extension.physics.box2d.util.Vector2Pool;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.ui.activity.LayoutGameActivity;
import org.andengine.ui.activity.SimpleLayoutGameActivity;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.input.touch.detector.PinchZoomDetector;
import org.json.JSONException;
import org.json.JSONObject;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.examplebox2dtest.R;

public class MultiplayerActivity extends LayoutGameActivity {

	Scene mScene;
	BitmapTextureAtlas projectileBmpAtlas;
	BitmapTextureAtlas blockBmpAtlas;
	ITextureRegion projtectileTxtrRegion;
	ITextureRegion blockTxtrRegion;
	ZoomCamera mCamera;
	
	PhysicsWorld physicsWorld;
	
	ArrayList<PhysicsEntityConnector> physicsObjects;
	RecorderUpdateHandler recorder;
	MessagePollingUpdateHandler messagePoller;
	
	ClientConnection connection;
	MultiplayerState state;
	
	DestructiveCollisionContactListener contactListener;
	TextView connectionTxt;
	SpriteLoader spriteLoader;
	PhysicsEntityConnectorFactory factory;
	ReplayUpdateHandler replayUpdateHandler;
	
	boolean canFire;
	boolean jsonReady;
	
	int gameId;
	int playerNum;
	int score;
	
	Vector2 p1FirePosition;
	Vector2 p2FirePosition;
	
	CameraController cameraControl;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		connection = null;
		Log.w("com.disgruntledbots", "OnCreate");

		this.physicsObjects = new ArrayList<PhysicsEntityConnector>();
		
		canFire = true;

		final EditText ipInput  = (EditText) findViewById(R.id.ipInput); 
		connectionTxt = (TextView) findViewById(R.id.title);
		
		state = state.INITIAL;
		
		Button button = (Button) findViewById(R.id.Button);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                reset();
            }
        });
        
        Button fireButton = (Button) findViewById(R.id.FireButton);
        fireButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                fire();
            }
        });
        
        Button jsonActivity = (Button) findViewById(R.id.viewJSON);
        jsonActivity.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
            	if(ipInput.getText().toString().compareTo(getResources().getString(R.string.enterIP)) != 0 )
            	{
            		connection = new ClientConnection(80, ipInput.getText().toString());
            		messagePoller = new MessagePollingUpdateHandler(MultiplayerActivity.this);
            		mScene.registerUpdateHandler(messagePoller);
            		connectionTxt.setText("Connecting");
            	}
				
            }
        });
        
        this.p1FirePosition = new Vector2(128f, 352f);
        this.p2FirePosition = new Vector2(972f, 352f);
	}
	
	@Override
	public Engine onCreateEngine(EngineOptions pEngineOptions)
	{	
		
		Log.w("com.disgruntledbots", "OnCreateEngine");
		Engine engine = new FixedStepEngine(pEngineOptions, 30);
		Log.w("com.disgruntledbots", "Finished OnCreateEngine");
		
		return engine;
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		Log.w("com.disgruntledbots", "OnCreateMenuOptions");
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public EngineOptions onCreateEngineOptions() {
		
		Log.w("com.disgruntledbots", "OnCreateEngineOptions");
		mCamera = new ZoomCamera(0,0, 800, 480);
		EngineOptions options = new EngineOptions(
				true, ScreenOrientation.LANDSCAPE_FIXED, new RelativeResolutionPolicy(1f), mCamera);
		Log.w("com.disgruntledbots", "Finished Engine Options");
		return options;
	}

	@Override
	protected int getLayoutID() {
		Log.w("com.disgruntledbots", "Get LayoutID");
		return R.layout.activity_main;
	}

	@Override
	protected int getRenderSurfaceViewID() {
		Log.w("com.disgruntledbots", "RenderSurfaceView");
		return R.id.gameSurfaceView;
	}

	@Override
	public void onPopulateScene(Scene pScene, OnPopulateSceneCallback pOnPopulateSceneCallback) throws Exception
	{
		Log.w("com.disgruntledbots", "onPopulateScene");
		
		this.contactListener = new DestructiveCollisionContactListener(this.physicsObjects);
		this.physicsWorld.setContactListener(contactListener);
		this.factory = new PhysicsEntityConnectorFactory(this.mEngine.getVertexBufferObjectManager(), physicsWorld, spriteLoader);
		
		PhysicsEntityConnector block0 = this.factory.newGlassBlock(500, 431);
		PhysicsEntityConnector block1 = this.factory.newGlassBlock(497, 382);
		PhysicsEntityConnector block2 = this.factory.newGlassBlock(493, 333);
		PhysicsEntityConnector block3 = this.factory.newGlassBlock(497, 284);
		PhysicsEntityConnector block4 = this.factory.newGlassBlock(500, 235);
		
		PhysicsEntityConnector block5 = this.factory.newStoneBlock(600, 431);
		PhysicsEntityConnector block6 = this.factory.newStoneBlock(597, 382);
		PhysicsEntityConnector block7 = this.factory.newStoneBlock(593, 333);
		PhysicsEntityConnector block8 = this.factory.newStoneBlock(597, 284);
		PhysicsEntityConnector block9 = this.factory.newStoneBlock(600, 235);

		this.physicsObjects.add(block0);
		this.physicsObjects.add(block1);
		this.physicsObjects.add(block2);
		this.physicsObjects.add(block3);
		this.physicsObjects.add(block4);
		
		this.physicsObjects.add(block5);
		this.physicsObjects.add(block6);
		this.physicsObjects.add(block7);
		this.physicsObjects.add(block8);
		this.physicsObjects.add(block9);

		//Attach Entities
		this.mScene.attachChild(block0.mSprite);
		this.mScene.attachChild(block1.mSprite);
		this.mScene.attachChild(block2.mSprite);
		this.mScene.attachChild(block3.mSprite);
		this.mScene.attachChild(block4.mSprite);
		
		this.mScene.attachChild(block5.mSprite);
		this.mScene.attachChild(block6.mSprite);
		this.mScene.attachChild(block7.mSprite);
		this.mScene.attachChild(block8.mSprite);
		this.mScene.attachChild(block9.mSprite);

		//Register Update Handlers
		this.recorder = new RecorderUpdateHandler(physicsObjects, this);
		this.replayUpdateHandler = new ReplayUpdateHandler(this);
		this.mScene.registerUpdateHandler(new OutOfBoundsUpdateHandler(this.mScene, physicsWorld, physicsObjects, -200, -200, 1000, 680));
		this.mScene.registerUpdateHandler(recorder);
		this.mScene.registerUpdateHandler(new ScoreKeeperUpdateHandler(this));
		this.mScene.registerUpdateHandler(replayUpdateHandler);
		pOnPopulateSceneCallback.onPopulateSceneFinished();
	}

	public void reset()
	{
//		PhysicsEntityConnector block0 = new PhysicsEntityConnector(600, 390, blockTxtrRegion, this.mEngine.getVertexBufferObjectManager(), physicsWorld, 10f, .6f, .25f);
//		PhysicsEntityConnector block1 = new PhysicsEntityConnector(594, 331, blockTxtrRegion, this.mEngine.getVertexBufferObjectManager(), physicsWorld, 10f, .6f, .25f);
//		PhysicsEntityConnector block2 = new PhysicsEntityConnector(582, 256, blockTxtrRegion, this.mEngine.getVertexBufferObjectManager(), physicsWorld, 10f, .6f, .25f);
//		PhysicsEntityConnector block3 = new PhysicsEntityConnector(594, 201, blockTxtrRegion, this.mEngine.getVertexBufferObjectManager(), physicsWorld, 10f, .6f, .25f);
//		PhysicsEntityConnector block4 = new PhysicsEntityConnector(600, 136, blockTxtrRegion, this.mEngine.getVertexBufferObjectManager(), physicsWorld, 10f, .6f, .25f); 
//		
//		this.physicsObjects.add(block0);
//		this.physicsObjects.add(block1);
//		this.physicsObjects.add(block2);
//		this.physicsObjects.add(block3);
//		this.physicsObjects.add(block4);
//		
//		//Attach Entities
//		this.mScene.attachChild(block0.mSprite);
//		this.mScene.attachChild(block1.mSprite);
//		this.mScene.attachChild(block2.mSprite);
//		this.mScene.attachChild(block3.mSprite);
//		this.mScene.attachChild(block4.mSprite);	
//		
//		canFire = true;
//		this.recorder.reset();
	}
	
	public void fire()
	{
		if(state == MultiplayerState.READY){
			PhysicsEntityConnector projectile; 
//			= new CircularBodyEntityConnector(
//					128, 352, projtectileTxtrRegion,
//					this.mEngine.getVertexBufferObjectManager(), physicsWorld,
//					20f, .5f, .1f);
			if(this.connection.playerNum == 1)
			{
				projectile = factory.newBasicBot((int)this.p1FirePosition.x, (int)this.p1FirePosition.y);
				projectile.mBody.setLinearVelocity(10f, -7f);
			}else
			{
				projectile = factory.newBasicBot((int)this.p2FirePosition.x, (int)this.p2FirePosition.y);
				projectile.mBody.setLinearVelocity(-10f, -7f);
			}
			
			this.mScene.attachChild(projectile.mSprite);
			this.physicsObjects.add(projectile);
			this.recorder.startRecording(projectile);
			
			
			
			
			state = MultiplayerState.FIRED;
			connectionTxt.setText("Fired");
		}
	}
	
	@Override
	public void onCreateResources(OnCreateResourcesCallback arg0)
			throws Exception {
		Log.w("com.disgruntledbots", "OnCreateResources");
		//Set Sprite Resource Folder
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("sprites/bots/");
		
		Log.w("com.disgruntledbots", "Declare Sprites");
		//Declare Projectile Sprite
		this.projectileBmpAtlas = new BitmapTextureAtlas(getTextureManager(), 64, 64); 
		this.projtectileTxtrRegion = 
				BitmapTextureAtlasTextureRegionFactory.
				createFromAsset(projectileBmpAtlas, this, "player_projectile.png", 0,0);
		//Declare Block Sprite
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("sprites/destructableObstacles/");
		this.blockBmpAtlas = new BitmapTextureAtlas(getTextureManager(), 64, 64); 
		this.blockTxtrRegion = 
				BitmapTextureAtlasTextureRegionFactory.
				createFromAsset(blockBmpAtlas, this, "block.png", 0,0);
		
		Log.w("com.disgruntledbots", "Load Sprites");
		//Load Assets for use in the scene
		projectileBmpAtlas.load();
		blockBmpAtlas.load();
		
		spriteLoader = new SpriteLoader(this);
 
		arg0.onCreateResourcesFinished();
	}

	@Override
	public void onCreateScene(OnCreateSceneCallback arg0) throws Exception {
		// TODO Auto-generated method stub
		Log.w("com.disgruntledbots", "Create Scene");
		mScene = new Scene();
		mScene.setBackground(new Background(256,256,256) );
		this.cameraControl = new CameraController(this.mCamera);
		
		physicsWorld = new FixedStepPhysicsWorld(30, new Vector2(0, 9.81f), false);
		mScene.registerUpdateHandler(physicsWorld);
		
		FixtureDef groundFix = PhysicsFactory.createFixtureDef(0, .25f, 1f);
		Rectangle ground = new Rectangle(0, 460, 1200, 10, this.mEngine.getVertexBufferObjectManager());
		PhysicsFactory.createBoxBody(physicsWorld, ground, BodyType.StaticBody, groundFix);
		ground.setColor(0f, 1f, .25f);
		mScene.attachChild(ground);
		
		mScene.setOnSceneTouchListener(cameraControl);
		arg0.onCreateSceneFinished(mScene);
	}
	
	public void recieveMessage(JSONObject message)
	{
		String messageStr;
		Log.i("MultiplayerActivity", "Recieved Message");
		try {
			messageStr = message.getString("Message");
			
			if(messageStr.compareTo("Rqst Received") == 0)
			{
				if(connection.playerNum == 1)
				{
					state = MultiplayerState.READY;

				}else if(connection.playerNum == 2)
				{
					state = MultiplayerState.WAITING;
					this.mCamera.setZoomFactor(1.0f);
					this.mCamera.setCenter(800, 240);
				}else{
					state = MultiplayerState.ERROR;
				}
			}else if(messageStr.compareTo("Turn Recieved") == 0)
			{
				state = MultiplayerState.WAITING;
			}else if(messageStr.compareTo("Turn") == 0)
			{
				state = MultiplayerState.REPLAYING;
				this.replayUpdateHandler.startReplay(message.getJSONObject("Turn Data"));
				state = MultiplayerState.READY;
			}else if(messageStr.compareTo("Winner Received") == 0)
			{
				state = MultiplayerState.FINISHED;
			}else if(messageStr.compareTo("Win") == 0)
			{
				state = MultiplayerState.FINISHED;
			}else if(messageStr.compareTo("Rqst Denied") == 0)
			{
				state = MultiplayerState.ERROR;
			}
			
		} catch (JSONException e) {
			this.state = MultiplayerState.ERROR;
			Log.e("Activity Message", e.getMessage(), e);
		}
	}
	
	public void turnFinished()
	{
		if(state == MultiplayerState.FIRED)
		{
			state = MultiplayerState.WAITING;
			connection.sendMessage(this.recorder.getJSON());
		}
	}
	
	public DamageablePhysicsEntity randomBot(int x, int y)
	{
		Random random = new Random(SystemClock.currentThreadTimeMillis());
		int num = random.nextInt(3);
		
		if(num == 0)
		{
			return factory.newBasicBot(x, y);
		}
		else if(num == 1)
		{
			return factory.newBombBot(x, y);
		}else{
			return factory.newEMPBot(x, y);
		}
	}
}
